package jwlee.testclassloader;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Method;

public class CompilingClassLoader extends ClassLoader {

	public Class<?> loadClass(String name, boolean resovle)
			throws ClassNotFoundException {
		System.out.println("CompilingClassLoader.loadClass() " + name);

		Class<?> clas = findLoadedClass(name);

		// 这里说明了包的表示
		String fileStub = name.replace('.', '/');

		String javaFilename = fileStub + ".java";
		String classFilename = fileStub + ".class";

		File javaFile = new File(javaFilename);
		File classFile = new File(classFilename);

		// 如果存在class文件就不编译
		if (javaFile.exists()
				&& (!classFile.exists() || javaFile.lastModified() > classFile
						.lastModified())) {
			try {
				if (!compile(javaFilename) || !classFile.exists()) {
					throw new ClassNotFoundException("ClassNotFoundExcetpion:"
							+ javaFilename);
				}
			} catch (IOException ie) {
				throw new ClassNotFoundException(ie.toString());
			}
		}

		try {
			byte[] raw = getBytes(classFilename);

			// 通过读入数据来构造一个类结构，这是核心
			clas = defineClass(name, raw, 0, raw.length);
		} catch (IOException ie) {
		}

		if (clas == null) {
			clas = findSystemClass(name);
		}

		System.out.println("findSystemClass:" + clas);

		if (resovle && clas != null) {
			resolveClass(clas);
		}

		if (clas == null) {
			throw new ClassNotFoundException(name);
		}

		return clas;
	}

	private boolean compile(String javaFile) throws IOException {
		System.out.println("CCL:Compiling " + javaFile + "...");
		// 调用系统的javac命令
		Process p = Runtime.getRuntime().exec("javac " + javaFile);
		try {
			// 其他线程都等待这个线程完成
			p.waitFor();
		} catch (InterruptedException ie) {
			System.err.println(ie);
		}
		int ret = p.exitValue();

		return ret == 0;
	}

	// 读取一个文件的内容
	private byte[] getBytes(String filename) throws IOException {
		File file = new File(filename);
		long len = file.length();
		byte[] raw = new byte[(int) len];

		FileInputStream fin = new FileInputStream(file);

		int r = fin.read(raw);
		if (r != len)
			throw new IOException("Can't read all," + r + "!=" + len);

		fin.close();

		return raw;
	}

	public static void main(String[] args) throws Exception {
		main1(new String[] { "jwlee.testclassloader.Hello", "mzj" });
	}

	public static void main1(String[] args) throws Exception {
		String progClass = args[0];
		String progArgs[] = new String[args.length - 1];
		System.arraycopy(args, 1, progArgs, 0, progArgs.length);

		CompilingClassLoader ccl = new CompilingClassLoader();

		Class clas = ccl.loadClass(progClass, true);

		System.out.println(ccl.getClass().getClassLoader());
		System.out.println(clas.getClassLoader());//?

		Object obj = clas.newInstance();

		// 返回一个class的type
		Class[] mainArgType = { (new String[0]).getClass() };
		Method method = clas.getMethod("init", mainArgType);

		Object argsArray[] = { progArgs };

		method.invoke(null, argsArray);

	}
}

class Hello {
	static {
		System.out.println("Hello everyone!");
	}

	Hello() {
		System.out.println("Hello()");
	}

	public static void init(String[] args) {
		if (args.length != 1) {
			System.err.println("Error,exit!");
			System.exit(1);
		}
		String name = args[0];
		System.out.println("Hello, " + name);
	}
}